#include "mut.h"
#include "muttree.h"


DWORD TREETRUNKVERTEX::FVF = D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1;

void CMUTTree::InitAll( TREETRUNKVERTEX* verts, WORD* tris, int& vindex, int& tindex, TREETRUNKVERTEX* lverts, WORD* ltris, int& lvindex, int& ltindex ){

	//All leaves
	RandTreeLeaf( lverts, ltris, lvindex, ltindex );

	//main trunk
	InitData( verts, tris, SegO, SegT, SegN, SegB, SegNum, SegSlice, TrunkBaseR, TrunkSegHeight, vindex, tindex );
	float RStep = TrunkBaseR / ( SegNum + 1 );
	float baseR = TrunkBaseR - SubTrunkStart * RStep;
	//sub trunks
	for ( int i = 0; i < SubTrunkEnd - SubTrunkStart; i++ ){
		InitData( verts, tris, SubO[i], SubT[i], SubN[i], SubB[i], SubTrunkSegNum, SubTrunkSegSlice, baseR, SubTrunkSegHeight, vindex, tindex );
		baseR -= RStep;
	}
}

void CMUTTree::RandTreeLeaf( TREETRUNKVERTEX* verts, WORD* tris, int& vindex, int& tindex ){

	float s = 150.0f;
	float step = 30.0f / 180 * D3DX_PI;
	int _vindex = vindex;
	D3DXVECTOR3 curO, curT, curN, curB;

	int start = 0;
	float range = SubTrunkSegNum - start;
	for ( int i = 0; i < SubTrunkNum; i++ ){
		for ( int l = 0; l < LeafPerTrunk; l++ ){
			float cur = start + rand() % 1000 / 1000.0f * range;
			int k = int( cur );
			curO = SubO[ i ][ k ];
			float lerp = cur - k;
			curO = curO + lerp * ( SubO[ i ][ k + 1 ] - curO );
			curN = SubN[ i ][ k ] + ( rand() % 1000 / 500.0f - 1.0f ) * SubT[ i ][ k ] + ( rand() % 1000 / 500.0f - 1.0f ) * SubB[ i ][ k ];
			D3DXVec3Cross( &curB, &curT, &curN );
			D3DXVec3Cross( &curT, &curN, &curB );
			D3DXVec3Normalize( &curN, &curN );
			D3DXVec3Normalize( &curT, &curT );
			D3DXVec3Normalize( &curB, &curB );
			for ( int j = 0; j < 6; j++, _vindex+=2 ){
				float radStart = rand() % 1000 / 500.0f;
				verts[ _vindex ].p = curO +  ( -s * cos( j * step + radStart ) ) * curT + ( j % 2 * s * 2 ) * curN + ( s * sin( j * step + radStart ) ) * curB;
				verts[ _vindex+1 ].p = curO +  ( s * cos( j * step + radStart ) ) * curT + ( j % 2 * s * 2 ) * curN + ( -s * sin( j * step + radStart ) ) * curB;
				verts[ _vindex ].uv = D3DXVECTOR2( 0, ( j + 1 ) % 2 );
				verts[ _vindex+1 ].uv = D3DXVECTOR2( 1, ( j + 1 ) % 2 );
				verts[ _vindex ].normal = D3DXVECTOR3( 0, (rand()%1000/500.0f) - 1.0f, 0 );
				verts[ _vindex+1 ].normal = verts[ _vindex ].normal;
			}
		}
	}


	int _tindex = tindex;
	for ( int i = 0; i < LeafVNumPerTrunk; i += 4, _tindex += 6 ){
		tris[ _tindex ] = vindex + i;
		tris[ _tindex+1 ] = vindex + i+2;
		tris[ _tindex+2 ] = vindex + i+1;

		tris[ _tindex+3 ] = vindex + i+2;
		tris[ _tindex+4 ] = vindex + i+3;
		tris[ _tindex+5 ] = vindex + i+1;
	}

	vindex = _vindex;
	tindex = _tindex;
}

void CMUTTree::RandTree( D3DXVECTOR3 pos ){
	D3DXVECTOR3 curO( pos );
	D3DXVECTOR3 curT( 1, 0, 0 );
	D3DXVECTOR3 curN( 0, 1, 0 );
	D3DXVECTOR3 curB( 0, 0, 1 );
	// main trunk
	for ( int i = 0; i < SegNum; i++ ){
		SegO[ i ] = curO;
		SegT[ i ] = curT;
		SegN[ i ] = curN;
		SegB[ i ] = curB;
		curN += ( rand() % 1000 / 3000.0f - 0.17f ) * curT + ( rand() % 1000 / 3000.0f - 0.17f ) * curB;
		D3DXVec3Normalize( &curN, &curN );
		D3DXVec3Cross( &curB, &curT, &curN );
		D3DXVec3Cross( &curT, &curN, &curB );
		D3DXVec3Normalize( &curB, &curB );
		D3DXVec3Normalize( &curT, &curT );
		curO += ( rand() % 200 / 1000.0f + 0.8f ) *  TrunkSegHeight * curN;
	}
	SegO[ SegNum ] = curO;

	// sub trunk
	int dirT[ SubTrunkNum ], dirB[ SubTrunkNum ], sumT = 0, sumB = 0;
	for ( int i = 0; i < SubTrunkNum; i++ ){
		dirT[i] = ( rand() % 2 ) ? 1 : -1;
		dirB[i] = ( rand() % 2 ) ? 1 : -1;
		sumT += dirT[i];
		sumB += dirB[i];
	}
	if ( sumT == SubTrunkNum || sumT == -SubTrunkNum ){
		int r = rand() % SubTrunkNum;
		dirT[r] = -dirT[r];
	}
	if ( sumB == SubTrunkNum || sumB == -SubTrunkNum ){
		int r = rand() % SubTrunkNum;
		dirB[r] = -dirB[r];
	}


	for ( int i = SubTrunkStart; i < SubTrunkEnd; i++ ){
		curO = SegO[ i ];
		curT = SegT[ i ];		

		curN = SegN[ i ] + SegT[ i ] * dirT[ i - SubTrunkStart ] * ( 0.5f +  rand () % 1000 / 2000.0f ) + SegB[ i ] * dirB[ i - SubTrunkStart ] * ( 0.5f +  rand () % 1000 / 2000.0f );

		D3DXVec3Normalize( &curN, &curN );
		D3DXVec3Cross( &curB, &curT, &curN );
		D3DXVec3Cross( &curT, &curN, &curB );
		D3DXVec3Normalize( &curT, &curT );
		D3DXVec3Normalize( &curB, &curB );
		int sub = i - SubTrunkStart;
		for ( int j = 0; j < SubTrunkSegNum; j++ ){
			SubO[ sub ][ j ] = curO;
			SubT[ sub ][ j ] = curT;
			SubN[ sub ][ j ] = curN;
			SubB[ sub ][ j ] = curB;
			curN += ( rand() % 1000 / 3000.0f - 0.17f ) * curT + ( rand() % 1000 / 3000.0f - 0.17f ) * curB;
			D3DXVec3Normalize( &curN, &curN );
			D3DXVec3Cross( &curB, &curT, &curN );
			D3DXVec3Cross( &curT, &curN, &curB );
			D3DXVec3Normalize( &curB, &curB );
			D3DXVec3Normalize( &curT, &curT );
			curO += ( rand() % 200 / 1000.0f + 0.8f ) *  SubTrunkSegHeight * curN;
		}
		SubO[sub][SubTrunkSegNum] = curO;
	}
}

void CMUTTree::InitData( TREETRUNKVERTEX* verts, WORD* tris, D3DXVECTOR3* curO, D3DXVECTOR3* curT, D3DXVECTOR3* curN, D3DXVECTOR3* curB, int segNum, int slice, float baseR, float segHeight, int& vindex, int& tindex ){
	int _vindex = vindex;
	float curR = baseR;
	float RStep = baseR / ( segNum + 1 );
	float RadStep = 2.0f * D3DX_PI / ( slice - 1 );
	float curRad = 0;
	for ( int i = 0; i < segNum; i++ ){
		curR -= RStep;
		for ( int j = 0; j < slice; j++, _vindex++ ){
			curRad = j * RadStep;
			verts[ _vindex ].normal = curR * cos( curRad ) * curT[i] + curR * sin( curRad ) * curB[i];
			verts[ _vindex ].p = curO[i] + verts[ _vindex ].normal;
			verts[ _vindex ].uv = D3DXVECTOR2( j / float( slice - 1 ), i % 2 );
		}
	}
	verts[ _vindex ].p = curO[ segNum ];
	verts[ _vindex++ ].uv = D3DXVECTOR2( 0, ( segNum + 1 ) % 2 );


	int _tindex = tindex;

	for ( int i = 0; i < segNum-1; i++ ){
		for ( int j = 0; j < slice; j++, _tindex += 6 ){
			tris[ _tindex ] = vindex + i * slice + j;
			tris[ _tindex+1 ] = vindex + ( i + 1 ) * slice + j;
			tris[ _tindex+2 ] = vindex + i * slice + ( j + 1 ) % slice;
			tris[ _tindex+3 ] = vindex + ( i + 1 ) * slice + j;
			tris[ _tindex+4 ] = vindex + ( i + 1 ) * slice + ( j + 1 ) % slice;
			tris[ _tindex+5 ] = vindex + i * slice + ( j + 1 ) % slice;
		}
	}
	int lastvert = _vindex - 1;
	for ( int j = 0; j < slice; j++, _tindex += 3 ){
		tris[ _tindex ] = vindex + ( segNum - 1 ) * slice + j;
		tris[ _tindex+1 ] = lastvert;
		tris[ _tindex+2 ] = vindex + ( segNum - 1 ) * slice + ( j + 1 ) % slice;
	}


	vindex = _vindex;
	tindex = _tindex;
}

//////////////////////////////////////////////////////////////////////////////

HRESULT CMUTTreeSet::Create( HANDLE hEvent, int num ){
	/*
	for ( int i = 0; i < tnum; i++ ){
		trees[ i ].RandTree( pos[i] );
	}*/
	/*
	LPDIRECT3DDEVICE9 pDevice = MUTState()->GetDevice();
	if ( !pDevice ) return E_FAIL;
	HRESULT hr = S_OK;
	vnum = tnum * ( SegNum * SegSlice + 1 + ( SubTrunkEnd - SubTrunkStart ) * ( SubTrunkSegNum * SubTrunkSegSlice + 1 ) );
	if ( FAILED( hr = pDevice->CreateVertexBuffer( vnum * sizeof ( TREETRUNKVERTEX ), 0, TREETRUNKVERTEX::FVF, D3DPOOL_MANAGED, &vb, NULL ) ) ){
		MUTDXErrorTrace( hr, L"treeset trunk vb failed" );
		return E_FAIL;
	}
	fnum = tnum * ( ( SegNum - 1 ) * SegSlice * 2 + SegSlice + ( SubTrunkEnd - SubTrunkStart ) * ( ( SubTrunkSegNum - 1 ) * SubTrunkSegSlice * 2 + SubTrunkSegSlice ) );
	if ( FAILED( hr = pDevice->CreateIndexBuffer( 3 * sizeof( WORD ) * fnum, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ib, NULL ) ) ){
		MUTDXErrorTrace( hr, L"treeset trunk ib failed" );
		return E_FAIL;
	}
	lvnum = tnum * LeafVNumPerTrunk;
	if ( FAILED( hr = pDevice->CreateVertexBuffer( lvnum * sizeof( TREETRUNKVERTEX ), 0, TREETRUNKVERTEX::FVF, D3DPOOL_MANAGED, &lvb, NULL ) ) ){
		MUTDXErrorTrace( hr, L"treeset leaf vb failed" );
		return E_FAIL;
	}
	lfnum = tnum * LeafPerTrunk * SubTrunkNum * 6;
	if ( FAILED( hr = pDevice->CreateIndexBuffer( 3 * sizeof( WORD ) * lfnum, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &lib, NULL ) ) ){
		MUTDXErrorTrace( hr, L"treeset leaf ib failed" );
		return E_FAIL;
	}

	int vindex = 0, tindex = 0, lvindex = 0, ltindex = 0;
	for ( int i = 0; i < tnum; i++ ){
		trees[i].InitAll( vb, ib, vindex, tindex, lvb, lib, lvindex, ltindex );
	}*/

	if ( !num ){
		tnum = num;
		return S_OK;
	}
	trees = new CMUTTree[ num ];
	if ( !trees ){
		MUTErrorTrace( L"treeset create failed" );
		return E_FAIL;
	}
	tnum = num;
	vnum = tnum * ( SegNum * SegSlice + 1 + ( SubTrunkEnd - SubTrunkStart ) * ( SubTrunkSegNum * SubTrunkSegSlice + 1 ) );
	fnum = tnum * ( ( SegNum - 1 ) * SegSlice * 2 + SegSlice + ( SubTrunkEnd - SubTrunkStart ) * ( ( SubTrunkSegNum - 1 ) * SubTrunkSegSlice * 2 + SubTrunkSegSlice ) );
	/*lvnum = tnum * LeafVNumPerTrunk;
	lfnum = tnum * LeafPerTrunk * SubTrunkNum * 6;*/

	MUTRequestVertexBuffer( hEvent, vnum * sizeof ( TREETRUNKVERTEX ), TREETRUNKVERTEX::FVF, vb );
	MUTRequestIndexBuffer( hEvent, 3 * sizeof( WORD ) * fnum, D3DFMT_INDEX16, ib );
	/*MUTRequestVertexBuffer( hEvent, lvnum * sizeof( TREETRUNKVERTEX ), TREETRUNKVERTEX::FVF, lvb );
	MUTRequestIndexBuffer( hEvent, 3 * sizeof( WORD ) * lfnum, D3DFMT_INDEX16, lib );*/

	return S_OK;
}

void CMUTTreeSet::InitData( D3DXVECTOR3 bias, D3DXVECTOR3* pos ){
	for ( int i = 0; i < tnum; i++ ){
		trees[ i ].RandTree( pos[i]+bias );
	}
	int vindex = 0, tindex = 0, lvindex = 0, ltindex = 0;
	for ( int i = 0; i < tnum; i++ ){
		trees[i].InitAll( (TREETRUNKVERTEX*)vertsVoid, (WORD*)trisVoid, vindex, tindex, (TREETRUNKVERTEX*)lvertsVoid, (WORD*)ltrisVoid, lvindex, ltindex );
	}
}

void CMUTTreeSet::RenderTrunk(){
	LPDIRECT3DDEVICE9 pDevice = MUTState()->GetDevice();
	pDevice->SetFVF( TREETRUNKVERTEX::FVF );
	pDevice->SetStreamSource( 0, vb, 0, sizeof( TREETRUNKVERTEX ) );
	pDevice->SetIndices( ib );
	pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, vnum, 0, fnum );
}

void CMUTTreeSet::RenderLeaf(){
	return;
	LPDIRECT3DDEVICE9 pDevice = MUTState()->GetDevice();
	pDevice->SetFVF( TREETRUNKVERTEX::FVF );
	pDevice->SetStreamSource( 0, lvb, 0, sizeof( TREETRUNKVERTEX ) );
	pDevice->SetIndices( lib );
	pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, lvnum, 0, lfnum );
}

void CMUTTreeSet::Release( HANDLE hEvent ){
	if ( hEvent ){
		if ( vb )
			MUTRequestRelease( hEvent, MUTRES_VB, vb );
		if ( lvb )
			MUTRequestRelease( hEvent, MUTRES_VB, lvb );
		if ( ib )
			MUTRequestRelease( hEvent, MUTRES_IB, ib );
		if ( lib )
			MUTRequestRelease( hEvent, MUTRES_IB, lib );
	}else{
		if ( vb )
			vb->Release();
		if ( lvb )
			lvb->Release();
		if ( ib )
			ib->Release();
		if ( lib )
			lib->Release();
	}
	if ( trees )
		delete[] trees;
	trees = 0;

	tnum = 0;
	lvb = vb = 0;
	lib = ib = 0;

	vertsVoid = lvertsVoid = trisVoid = ltrisVoid = 0;
	vnum = fnum = lvnum = lfnum = 0;
}